package com.example.draggableview;

import java.util.Arrays;
import java.util.HashMap;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.TranslateAnimation;
import android.widget.LinearLayout;
import android.widget.TextView;

/**
 * 自定义可以进行拖拽排序的布局类
 * 
 * @author lucher
 * 
 */
public class DraggableSortLayout1 extends LinearLayout implements OnLongClickListener {

	private static final String TAG = "DraggableSortLayout";

	// 子view之间的间距
	private static final int VIEW_MARGIN = 5;
	private AccelerateInterpolator acInterpolator = new AccelerateInterpolator();

	// 对应的号码
	private int number;

	/**
	 * 临时存放位置信息
	 */
	private final Rect tempRect = new Rect();

	// 拖动状态，初始状态和拖动状态以及拖动结束
	private static int STATE_IDLE = 1;
	private static int STATE_DRAG = 2;
	private static int STATE_END_DRAG = 3;
	// 当前拖动状态
	private int state = STATE_IDLE;

	// 拖动视图，需要交换位置的视图
	private View currentDragView, lastSwapView;

	private DragListener mListener;
	private Context mContext;

	private DraggableLayoutParams lp;

	// 上一个x坐标，用来作为刷新拖拽图标的参照
	private int oldX;
	// 拖拽视图应该落入的坐标
	private int[] targetPosition = new int[2];
	// 拖拽图标拖动时的x坐标
	private int startX = 0;

	public DraggableSortLayout1(Context context, AttributeSet attrs) {
		super(context, attrs);
		mContext = context;
	}

	/**
	 * 设置拖拽接口
	 * 
	 * @param listener
	 */
	public void setDragListener(DragListener listener) {
		mListener = listener;
	}

	/**
	 * 根据单词数组初始化视图
	 * 
	 * @param number
	 * @param words
	 */
	public void init(int number, String[] words) {
		// TODO Auto-generated method stub
		this.number = number;

		int size = words.length;
		for (int i = 0; i < size; i++) {
			TextView text = new TextView(mContext);
			DraggableLayoutParams lp = new DraggableLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
			text.setLayoutParams(lp);
			text.setText(words[i]);
			text.setTag(i);
			text.setTextSize(60);
			text.setBackgroundResource(R.drawable.tv_bg_normal);
			this.addView(text);

			text.setOnLongClickListener(this);
		}
	}

	int l, t;

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		switch (event.getAction() & MotionEvent.ACTION_MASK) {
		case MotionEvent.ACTION_MOVE:
			handleMoveEvent(event);
			break;
		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_CANCEL:
			if (state == STATE_DRAG) {
				// sortAllViews(event);
				state = STATE_END_DRAG;
				currentDragView.setBackgroundResource(R.drawable.tv_bg_normal);
				lp = (DraggableLayoutParams) currentDragView.getLayoutParams();
				lp.left = targetPosition[0];
				lp.top = targetPosition[1];

				getSortedWords();
				requestLayout();
			}
			break;
		}

		return true;
	}

	/**
	 * 处理move事件
	 * 
	 * @param event
	 */
	private void handleMoveEvent(MotionEvent event) {

		// TODO Auto-generated method stub
		if (state == STATE_DRAG) {
			int distance = oldX - startX;// 触摸点与文本左边距离
			// Log.d("lucher", "distance =" + distance);
			DraggableLayoutParams lp = (DraggableLayoutParams) currentDragView.getLayoutParams();
			lp.left = (int) event.getX() - distance;
			lp.top = t;
			currentDragView.layout(lp.left, lp.top, lp.left + currentDragView.getWidth(), lp.top + currentDragView.getHeight());

			// View swapView = findSwapView((int) event.getX(), (int)
			// event.getY());
			//
			// if (swapView != null) {
			// // Log.d(TAG, "find a view text=" + ((TextView)
			// // swapView).getText().toString() + " tag=" +
			// // swapView.getTag() + " current tag=" +
			// // currentDragView.getTag());
			// if (lastSwapView != swapView) {// 需要交换顺序
			// Log.d(TAG, "need to swap order :" + ((TextView)
			// swapView).getText().toString());
			// // swapView(swapView, currentDragView);
			// }
			// }
			//
			// lastSwapView = swapView;
			updateViewPosition((int) event.getX());
		}
	}

	private void updateViewPosition(int x) {
		// TODO Auto-generated method stub
		int count = this.getChildCount();
		for (int i = 0; i < count; i++) {
			final View child = this.getChildAt(i);
			DraggableLayoutParams lp = (DraggableLayoutParams) child.getLayoutParams();
			int left = lp.left;
			int right = lp.left + lp.width;
			int width = lp.width;
			if (x > targetPosition[0]) {// 向后拖
				if (left > targetPosition[0] && left < x && child != currentDragView) {
					// lp.left = lp.left - currentDragView.getWidth() -
					// VIEW_MARGIN;
					distance =  - currentDragView.getWidth() - VIEW_MARGIN;
					targetPosition[0] += (width + VIEW_MARGIN);
					Log.d("lucher", "front swap a view =" + ((TextView) child).getText().toString());
				}
			} else if (x < targetPosition[0]) {// 向前拖
				if (right > x && right < targetPosition[0] && child != currentDragView) {
					lp.left = lp.left + currentDragView.getWidth() + VIEW_MARGIN;
					targetPosition[0] -= (width + VIEW_MARGIN);
					Log.d("lucher", "back swap a view =" + ((TextView) child).getText().toString());
				}
			}

			TranslateAnimation translateAnimation = new TranslateAnimation(0, distance, 0, 0);
			translateAnimation.setDuration(200);
			translateAnimation.setInterpolator(acInterpolator);
			child.startAnimation(translateAnimation);
			translateAnimation.setAnimationListener(new AnimationListener() {

				@Override
				public void onAnimationStart(Animation animation) {
					// TODO Auto-generated method stub

				}

				@Override
				public void onAnimationRepeat(Animation animation) {
					// TODO Auto-generated method stub

				}

				@Override
				public void onAnimationEnd(Animation animation) {
					// TODO Auto-generated method stub
					child.clearAnimation();
					// TranslateAnimation anim = new TranslateAnimation(0, 0, 0,
					// 0);
					// swapView.startAnimation(anim);
					DraggableLayoutParams lp = (DraggableLayoutParams) child.getLayoutParams();
					lp.left = lp.left + distance;

					child.setLayoutParams(lp);
					child.requestLayout();
				}
			});
		}

	}

	/**
	 * 根据落入的坐标对视图进行排序
	 */
	private void sortAllViews(MotionEvent event) {

		int index = 0; // 记录需要落入的索引
		int minDistance = 10000; // 记录最小距离
		View swapView = null;

		int x = (int) event.getX();
		int count = this.getChildCount();
		for (int i = 0; i < count; i++) {
			View child = this.getChildAt(i);
			if (child == currentDragView) {
				continue;
			}

			int left = child.getLeft();
			int right = child.getRight();
			int middle = (left + right) / 2;

			int distance = Math.abs(middle - x);
			if (minDistance > distance) {
				minDistance = distance;
				index = i + 1;
				swapView = child;
			}
		}

		if (x < swapView.getLeft()) {
			index = index - 1;
		}

		// this.removeView(currentDragView);
		// this.addView(currentDragView, index);

		requestLayout();
	}

	/**
	 * 获取排好序的单词
	 */
	private void getSortedWords() {
		// TODO Auto-generated method stub
		int count = this.getChildCount();
		String[] result = new String[count];
		for (int i = 0; i < count; i++) {
			View child = this.getChildAt(i);
			result[i] = ((TextView) child).getText().toString();
		}
		mListener.onDragEnd(number, result);
	}

	/**
	 * 按照tag重新给view排序
	 */
	private void resetAllViewsByTag() {
		// TODO Auto-generated method stub
		int count = this.getChildCount();
		HashMap<Integer, View> map = new HashMap<Integer, View>();
		for (int i = 0; i < count; i++) {
			View child = this.getChildAt(i);
			int tag = (Integer) child.getTag();
			map.put(tag, child);
		}

		this.removeAllViews();

		Object[] key = map.keySet().toArray();
		Arrays.sort(key);

		for (int i = 0; i < key.length; i++) {
			this.addView(map.get(i));
		}
		requestLayout();
	}

	/**
	 * 交换视图位置
	 * 
	 * @param swapView
	 *            待交换视图
	 * @param currentDragView
	 *            当前拖拽视图
	 */
	int distance; // 滑动距离

	@SuppressLint("NewApi")
	private void swapView(final View swapView, View currentDragView) {
		// TODO Auto-generated method stub
		lp = (DraggableLayoutParams) swapView.getLayoutParams();
		int left = lp.left;
		int top = lp.top;

		// if (left > targetPosition[0]) {// 向后拖
		// ObjectAnimator oa = ObjectAnimator.ofFloat(swapView, View.X, left,
		// targetPosition[0]);
		// // lp.left = targetPosition[0];
		// oa.setDuration(200);
		// // oa.start();
		// targetPosition[0] = targetPosition[0] + lp.width + VIEW_MARGIN;
		// targetPosition[1] = top;
		// } else {// 向前拖
		// ObjectAnimator oa = ObjectAnimator.ofFloat(swapView, View.X, left,
		// left + currentDragView.getWidth() + VIEW_MARGIN);
		// oa.setDuration(200);
		// // oa.start();
		// targetPosition[0] = left;
		// targetPosition[1] = top;
		//
		// // lp.left = left + currentDragView.getWidth() + VIEW_MARGIN;
		// }

		distance = 0; // 滑动距离
		if (left > targetPosition[0]) {// 向后拖
			distance = -currentDragView.getWidth() - VIEW_MARGIN;
			targetPosition[0] = targetPosition[0] + lp.width + VIEW_MARGIN;
			targetPosition[1] = top;
		} else {// 向前拖
			distance = currentDragView.getWidth() + VIEW_MARGIN;
			targetPosition[0] = left;
			targetPosition[1] = top;
		}

		TranslateAnimation translateAnimation = new TranslateAnimation(0, distance, 0, 0);
		translateAnimation.setDuration(200);
		translateAnimation.setInterpolator(acInterpolator);
		swapView.startAnimation(translateAnimation);

		translateAnimation.setAnimationListener(new AnimationListener() {

			@Override
			public void onAnimationStart(Animation animation) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onAnimationRepeat(Animation animation) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onAnimationEnd(Animation animation) {
				// TODO Auto-generated method stub
				swapView.clearAnimation();
				// TranslateAnimation anim = new TranslateAnimation(0, 0, 0, 0);
				// swapView.startAnimation(anim);
				DraggableLayoutParams lp = (DraggableLayoutParams) swapView.getLayoutParams();
				lp.left = lp.left + distance;

				swapView.setLayoutParams(lp);
				swapView.requestLayout();
			}
		});
	}

	/**
	 * 寻找需要交换的视图
	 * 
	 * @param x
	 * @param y
	 * @return
	 */
	private View findSwapView(int x, int y) {
		// TODO Auto-generated method stub
		View view = null;
		int childCount = this.getChildCount();
		Log.e(TAG, "--------------------------childCount=" + childCount);
		for (int i = 0; i < childCount; i++) {
			View child = this.getChildAt(i);

			// 获取子控件的位置
			Rect rect = tempRect;
			child.getHitRect(rect);

			Log.d(TAG, ((TextView) child).getText().toString() + ": left:" + child.getLeft() + " right:" + child.getRight() + " hitleft=" + rect.left
					+ " hitright=" + rect.right);

			if (x > rect.left && x < rect.right) {
				return child;
			}
		}

		return view;
	}

	/**
	 * 开始拖拽
	 * 
	 * @param view
	 */
	private void startDrag(View view) {
		state = STATE_DRAG;
		currentDragView = view;

		lp = (DraggableLayoutParams) currentDragView.getLayoutParams();
		targetPosition[0] = lp.left;
		targetPosition[1] = lp.top;
		startX = lp.left;

		view.setBackgroundResource(R.drawable.tv_bg_drag);
		bringChildToFront(view);
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		if (state == STATE_DRAG) {
			switch (event.getAction() & MotionEvent.ACTION_MASK) {
			case MotionEvent.ACTION_UP:
				state = STATE_END_DRAG;
				currentDragView.setBackgroundResource(R.drawable.tv_bg_normal);
				break;
			}

			return true;
		} else {
			switch (event.getAction() & MotionEvent.ACTION_MASK) {
			case MotionEvent.ACTION_DOWN:
				oldX = (int) event.getX();
				break;
			}
		}
		return false;

	}

	/**
	 * 监听拖拽状态
	 * 
	 * @author lucher
	 * 
	 */
	public interface DragListener {
		/**
		 * 拖拽开始
		 */
		public void onDragStart();

		/**
		 * 拖拽结束
		 * 
		 * @param number
		 * @param result
		 */
		public void onDragEnd(int number, String[] result);
	}

	@Override
	public boolean onLongClick(View v) {
		// TODO Auto-generated method stub
		this.startDrag(v);
		return false;
	}

	/**
	 * 提交答案
	 * 
	 * @param result
	 */
	public boolean submit(int[] result) {

		int count = this.getChildCount();
		if (result.length != count) {// 长度不一样则出问题了，直接返回错误
			return false;
		}

		for (int i = 0; i < count; i++) {
			TextView child = (TextView) this.getChildAt(i);
			if (result[i] == 0) {
				child.setTextColor(Color.RED);
			}
		}
		return true;
	}

	@Override
	protected void onLayout(boolean arg0, int l, int t, int r, int b) {
		Log.d(TAG, "layout..........................");
		final int count = getChildCount();
		int childLeft = getPaddingLeft();
		int childTop = getPaddingTop();
		for (int i = 0; i < count; i++) {
			final View child = this.getChildAt(i);
			DraggableLayoutParams lp = (DraggableLayoutParams) child.getLayoutParams();

			int width = child.getMeasuredWidth();
			int height = child.getMeasuredHeight();

			if (state == STATE_IDLE) {
				childLeft += VIEW_MARGIN;
				lp.left = childLeft;
				lp.top = childTop;
				lp.width = width;
				lp.height = height;

				child.layout(childLeft, childTop, childLeft + width, childTop + height);
				childLeft += width;
				Log.e(TAG, childLeft + "," + childTop + "," + (childLeft + width) + "," + (childTop + height));
			} else {
				child.layout(lp.left, lp.top, lp.left + width, lp.top + height);
			}

		}

	}

	/**
	 * 自定义布局参数类
	 * 
	 * @author Lucher
	 * 
	 */
	private class DraggableLayoutParams extends LinearLayout.LayoutParams {

		// 距离左边和上边距离
		int left, top;

		public DraggableLayoutParams(int width, int height) {
			super(width, height);
		}
	}

}
